/**
 * Register file.
 * The register file could be read in anytime by assign `raddr1/2` and the
 * output will showup in `out1/2` after a combinational delay.
 * For writing, you need to setup `waddr` and `in` before a posedge of `clk`,
 * and the written data will be available in the next clock. If you read and
 * write the same address within one clock, the output of `out` is unpredictable.
 * Using `reset` to clear the whole register file and each register will be set
 * to zero.
 **/
module Reg_file(raddr1, raddr2, raddr3, waddr, clk, wen, in, out1, out2, out3, reset, r31);
   parameter DATA_WIDTH = 32;
   parameter REGFILE_WIDTH = 5;

   //pin declarations
   input wire [REGFILE_WIDTH-1:0] raddr1, raddr2, raddr3, waddr;
   input wire                     wen, clk;
   input wire [DATA_WIDTH-1:0]    in;
   output wire [DATA_WIDTH-1:0]   out1, out2, out3, r31;
   input wire                     reset;

   //memory declarations
   reg [DATA_WIDTH - 1:0]    mem[0:(1 << (REGFILE_WIDTH) )- 1];
   integer                   i;

   //write logic
   always @(posedge clk or posedge reset) begin
      if (reset) begin
         for (i = 0; i < (1 << (REGFILE_WIDTH)) ; i=i+1) begin
            mem[i] <= 32'b0; // TODO: should be DATA_WIDTH'b0; But not know hot wo do.
         end
      end
      else if (wen && waddr != 0) begin
         mem[waddr] <= in;
      end
   end
   assign out1 = (raddr1 == 0? 0 : (raddr1 == waddr && wen ? in : mem[raddr1]));
   assign out2 = (raddr2 == 0? 0 : (raddr2 == waddr && wen ? in : mem[raddr2]));
   assign out3 = (raddr3 == 0? 0 : (raddr3 == waddr && wen ? in : mem[raddr3]));
   assign r31 = mem[31];

endmodule
